﻿using System;
using System.Collections.Generic;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YJKArchUtils.Utils;
using YJKLoopSearch;

namespace YJKLuthernWindow
{
	public class WindowGeometryExtractor
	{
		public WindowGeometryExtractor(ExternalCommandData cmdData)
		{
			this.m_Revit = cmdData;
			this.m_Doc = this.m_Revit.Application.ActiveUIDocument.Document;
		}

		public void ExtractWindowGeometryInfo(FamilySymbol symbol, ref List<List<EdgeInfo>> windowLoops, ref List<bool> isGlass, ref List<XYZ> profileLoop)
		{
			this.m_FamilySymbol = symbol;
			this.AcitveFamilySymbol();
			List<List<EdgeInfo>> windowLoops2 = new List<List<EdgeInfo>>();
			this.GetLegendEdgeLoopList(ref windowLoops, ref isGlass, ref windowLoops2);
			this.GetProfileLoop(windowLoops2, ref profileLoop);
		}

		private void AcitveFamilySymbol()
		{
			Transaction transaction = new Transaction(this.m_Revit.Application.ActiveUIDocument.Document);
			transaction.Start("acitve family symbol");
			try
			{
				RevitVersionFuncs.FamilySymbolActivate(this.m_FamilySymbol);
			}
			catch (Exception)
			{
				transaction.RollBack();
			}
			transaction.Commit();
		}

		private void GetLegendEdgeLoopList(ref List<List<EdgeInfo>> faceEdgeLoopList, ref List<bool> isGlass, ref List<List<EdgeInfo>> profileEdgeLoopList)
		{
			List<bool> list = new List<bool>();
			List<Face> faceWithFamilyInstance = this.GetFaceWithFamilyInstance(ref list);
			List<PlanarFace> list2 = new List<PlanarFace>();
			int i = 0;
			foreach (Face face in faceWithFamilyInstance)
			{
				new List<List<EdgeInfo>>();
				foreach (List<EdgeInfo> item in this.GetEdgeLoopListWithFace(face))
				{
					faceEdgeLoopList.Add(item);
					isGlass.Add(list[i]);
				}
				if (face.GetType() == typeof(PlanarFace))
				{
					PlanarFace planarFace = face as PlanarFace;
					if (planarFace.FaceNormal().IsAlmostEqualTo(XYZ.BasisY) || planarFace.FaceNormal().IsAlmostEqualTo(-XYZ.BasisY))
					{
						list2.Add(planarFace);
					}
				}
				i++;
			}
			if (list2.Count == 0)
			{
				return;
			}
			list2.Sort((PlanarFace left, PlanarFace right) => left.Area.CompareTo(right.Area));
			List<PlanarFace> list3 = new List<PlanarFace>();
			if (list2.Count > 20)
			{
				for (i = 0; i < (int)((double)list2.Count / 5.0); i++)
				{
					list3.Add(list2[i]);
				}
			}
			else
			{
				list3.AddRange(list2);
			}
			foreach (Face face2 in list2)
			{
				new List<List<EdgeInfo>>();
				foreach (List<EdgeInfo> item2 in this.GetEdgeLoopListWithFace(face2))
				{
					profileEdgeLoopList.Add(item2);
				}
			}
		}

		private void GetProfileLoop(List<List<EdgeInfo>> windowLoops, ref List<XYZ> profileLoop)
		{
			Transform transform = RevitVersionFuncs.CreateRotationAtPoint(XYZ.BasisX, -Math.PI*.5, XYZ.Zero);
			Transform inverse = transform.Inverse;
			List<Pole2D> list = new List<Pole2D>();
			foreach (List<EdgeInfo> list2 in windowLoops)
			{
				foreach (EdgeInfo edgeInfo in list2)
				{
					XYZ xyz = this.FormatPt(this.To2D(Geometry.TransformPoint(edgeInfo.StartPoint, transform)));
					XYZ xyz2 = this.FormatPt(this.To2D(Geometry.TransformPoint(edgeInfo.EndPoint, transform)));
					if (!xyz.IsAlmostEqualTo(xyz2))
					{
						Pole2D item = Pole2D.NewStructure2DPole(ElementId.InvalidElementId, xyz, xyz2, 0.0, 0.0);
						list.Add(item);
					}
				}
			}
			List<List<Curve>> fullFloorEdgeLoops = new StructureLoopSearcher(this.m_Revit).GetFullFloorEdgeLoops(list, StructureLoopSearcher.SearchEdgeLocation.SEL_Outside);
			if (fullFloorEdgeLoops.Count == 0)
			{
				return;
			}
			foreach (Curve curve in fullFloorEdgeLoops[0])
			{
				XYZ xyz3 = Geometry.TransformPoint(curve.GetEndPoint(0), inverse);
				xyz3 = new XYZ(Common.FeetToMM(xyz3.X), Common.FeetToMM(xyz3.Y), Common.FeetToMM(xyz3.Z));
				profileLoop.Add(xyz3);
			}
		}

		private XYZ FormatPt(XYZ pt)
		{
			double num = Convert.ToDouble(pt.X.ToString("f3"));
			double num2 = Convert.ToDouble(pt.Y.ToString("f3"));
			double num3 = Convert.ToDouble(pt.Z.ToString("f3"));
			return new XYZ(num, num2, num3);
		}

		private XYZ To2D(XYZ pt)
		{
			return new XYZ(pt.X, pt.Y, 0.0);
		}

		private List<Face> GetFaceWithFamilyInstance(ref List<bool> isGlassWithFace)
		{
			List<Face> list = new List<Face>();
			Options options = new Options();
			options.ComputeReferences = true;
			options.DetailLevel = (ViewDetailLevel)2;
			GeometryElement geometryElement = this.m_FamilySymbol.get_Geometry(options);
			if (geometryElement == null)
			{
				return list;
			}
			foreach (GeometryObject geometryObject in geometryElement)
			{
				Solid solid = geometryObject as Solid;
				if (!(solid == null))
				{
					GraphicsStyle graphicsStyle = this.m_Doc.GetElement(solid.GraphicsStyleId) as GraphicsStyle;
					if (graphicsStyle != null && graphicsStyle.GraphicsStyleCategory.Name.CompareTo("玻璃") != 0)
					{
						foreach (object obj in solid.Faces)
						{
							Face item = (Face)obj;
							list.Add(item);
							isGlassWithFace.Add(false);
						}
					}
				}
			}
			return list;
		}

		private List<List<EdgeInfo>> GetLoopsByMesh(Mesh mesh)
		{
			List<List<EdgeInfo>> list = new List<List<EdgeInfo>>();
			int numTriangles = mesh.NumTriangles;
			for (int i = 0; i < numTriangles; i++)
			{
				MeshTriangle meshTriangle = mesh.get_Triangle(i);
				List<EdgeInfo> list2 = new List<EdgeInfo>();
				XYZ xyz = meshTriangle.get_Vertex(0);
				XYZ xyz2 = meshTriangle.get_Vertex(1);
				XYZ xyz3 = meshTriangle.get_Vertex(2);
				EdgeInfo item = new EdgeInfo(xyz, xyz2, 0.0);
				list2.Add(item);
				EdgeInfo item2 = new EdgeInfo(xyz2, xyz3, 0.0);
				list2.Add(item2);
				EdgeInfo item3 = new EdgeInfo(xyz3, xyz, 0.0);
				list2.Add(item3);
				list.Add(list2);
			}
			return list;
		}

		private List<List<EdgeInfo>> GetEdgeLoopListWithFace(Face face)
		{
			List<List<EdgeInfo>> list = new List<List<EdgeInfo>>();
			if (face.EdgeLoops.Size > 1 || face.GetType() != typeof(PlanarFace))
			{
				Mesh mesh = face.Triangulate();
				list.AddRange(this.GetLoopsByMesh(mesh));
				return list;
			}
			foreach (object obj in face.EdgeLoops)
			{
				EdgeArray edgeArray = (EdgeArray)obj;
				List<EdgeInfo> list2 = new List<EdgeInfo>();
				foreach (object obj2 in edgeArray)
				{
					Curve curve = ((Edge)obj2).AsCurve();
					if (curve.GetType() == typeof(Line))
					{
						EdgeInfo item = new EdgeInfo(curve.GetEndPoint(0), curve.GetEndPoint(1), 0.0);
						list2.Add(item);
					}
					else
					{
						IList<XYZ> list3 = curve.Tessellate();
						for (int i = 0; i < list3.Count - 1; i++)
						{
							EdgeInfo item2 = new EdgeInfo(list3[i], list3[i + 1], 0.0);
							list2.Add(item2);
						}
					}
				}
				list.Add(list2);
			}
			return list;
		}

		private ExternalCommandData m_Revit;

		private Document m_Doc;

		private FamilySymbol m_FamilySymbol;
	}
}
